package com.wangijun.yuan.web.service;

import cn.hutool.core.lang.Dict;
import cn.hutool.extra.template.Template;
import cn.hutool.extra.template.TemplateConfig;
import cn.hutool.extra.template.TemplateEngine;
import cn.hutool.extra.template.TemplateUtil;
import com.wangijun.yuan.web.base.CommonResult;
import com.wangijun.yuan.core.util.JdbcMap;
import com.wangijun.yuan.web.util.YuanWebUtil;
import jakarta.mail.MessagingException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 邮件业务类
 *
 * @author qzz
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MailService {

    static class SendCount {
        private final static String mapKey = "send-email";

        private static Map<String, Integer> getMap() {
            return JdbcMap.getMap(JdbcMap.MapName.sendCount);
        }

        public static Integer count() {
            return getMap().get(mapKey) == null ? 0 : getMap().get(mapKey);
        }

        public static void add() {
            getMap().put(mapKey, getMap().get(mapKey) == null ? 0 : getMap().get(mapKey) + 1);
        }

        public static void reset() {
            getMap().put(mapKey, 0);
        }
    }

    /**
     * 注入邮件工具类
     */
    private final JavaMailSenderImpl javaMailSender;
    private final StringRedisTemplate stringRedisTemplate;


    @Value("${spring.mail.username}")
    private String sendMailer;


    public ValueOperations<String, String> getOpsValue() {
        return stringRedisTemplate.opsForValue();
    }

    /**
     * 检测邮件信息类
     */
    private void checkMail(String to, String subject, String text) {
        if (StringUtils.isEmpty(to)) {
            throw new RuntimeException("邮件收信人不能为空");
        }
        if (StringUtils.isEmpty(subject)) {
            throw new RuntimeException("邮件主题不能为空");
        }
        if (StringUtils.isEmpty(text)) {
            throw new RuntimeException("邮件内容不能为空");
        }
    }

    /**
     * 功能描述: 发送Html格式邮件
     *
     * @param to      发给谁
     * @param subject 邮件标题
     * @param content 邮件内容
     * @author wlf 2024/3/22 11:17
     */
    private void sendHtmlMailMessage(String to, String subject, String content) {  // 发送成功一次，添加一次
        checkMail(to, subject, content);
        if (SendCount.count() > 50) {
            throw new RuntimeException("今日邮箱验证次数已用完,无法验证");
        }
        try {
            //true 代表支持复杂的类型
            MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(javaMailSender.createMimeMessage(), true);
            //邮件发信人
            mimeMessageHelper.setFrom(sendMailer);
            //邮件收信人  1或多个
            mimeMessageHelper.setTo(to.split(","));
            //邮件主题
            mimeMessageHelper.setSubject(subject);
            //邮件内容   true 代表支持html
            mimeMessageHelper.setText(content, true);
            //邮件发送时间
            mimeMessageHelper.setSentDate(new Date());

            //发送邮件
            javaMailSender.send(mimeMessageHelper.getMimeMessage());
            log.info("发送邮件成功：" + sendMailer + "->" + to);
            // 发送成功一次，添加一次
            SendCount.add();
        } catch (MessagingException e) {
            log.info("发送邮件失败：" + e.getMessage());
        }
    }

    /**
     * 功能描述: 重置发送次数
     *
     * @author wlf 2024/3/22 17:32
     */
    public void restSendNum() {
        SendCount.reset();
    }


    /**
     * 功能描述: 发送验证码
     *
     * @param email   发送邮箱地址
     * @param subject 标题
     * @author wlf 2024/3/22 11:21
     */
    private void sendCode(String email, String subject, String operate) {
        // 发送验证码操作间隔后端校验
        final String codeSendFlag = "codeSendFlag" + "-" + email;

        if (getOpsValue().get(codeSendFlag) != null) {
            CommonResult.error("请不要多次发送验证码！验证码重发剩余时间：" + stringRedisTemplate.getExpire(codeSendFlag, TimeUnit.SECONDS) + ", 单位秒");
        }
        String code = YuanWebUtil.randNumStr(6);

        if (code.equals(getOpsValue().get(email))) {
            code = YuanWebUtil.randNumStr(6);
        }
        // 写入Redis
        getOpsValue().set(email, code, 300, TimeUnit.SECONDS);
        TemplateEngine engine =
                TemplateUtil.createEngine(new TemplateConfig("email-template",
                        TemplateConfig.ResourceMode.CLASSPATH));
        Template template = engine.getTemplate("auth-code.ftlh");
        String content = template.render(Dict.create()
                .set("code", code)
                .set("operate", operate)
        );
        sendHtmlMailMessage(email, subject, content);

        // 发送验证码成功过后写入一个有效期为60的key,在key未消失
        getOpsValue().set(codeSendFlag, "", 60, TimeUnit.SECONDS);
    }


    /**
     * 功能描述: 发送认证邮箱验证码
     *
     * @author wlf 2024/3/22 11:21
     */
    public void sendChangePdCode(String email) {
        sendCode(email, "[YuanBlog] 修改密码", "修改密码");
    }


    /**
     * 功能描述: 发送登录验证码
     *
     * @author wlf 2024/3/22 11:21
     */
    public void sendLoginCode(String email) {
        sendCode(email, "[YuanBlog] 登录认证", "登录");
    }

}
